#pragma once

/*
  These templates allow us to acquire the beginning and end of containers and arrays
  identically.  When used in loops, they will kill any chance of us overrunning a
  naked array.

  NB When using the end functions you get the first out-of-range element!  E.g. if you
     have an array like int array[80] then cpac::end(array) will return the address of
     array[80].  This is by design such that it matches how container iterators work.
     When writing a for loop, use the same structure as for containers.
     i.e. for(int* iterator cpac::begin(array); iterator != cpac::end(array); ++iterator)
          {
              ...
          }
*/

#include <iterator>

namespace cpac
{

    template< class _Container >
    typename _Container::iterator begin(_Container& in_container)
    {
        return (in_container.begin());
    }

    template< class _Container >
    typename _Container::const_iterator begin(_Container const& in_container)
    {
        return (in_container.begin());
    }

    template< typename _Type, size_t _Size >
    _Type* begin(_Type(&in_array)[_Size])
    {
        return (&in_array[0]);
    }

    template< typename _Type, size_t _Size >
    _Type const* begin(_Type const (&in_array)[_Size])
    {
        return (&in_array[0]);
    }

    template< class _Container >
    typename _Container::iterator end(_Container& in_container)
    {
        return (in_container.end());
    }

    template< class _Container >
    typename _Container::const_iterator end(_Container const& in_container)
    {
        return (in_container.end());
    }

    template< typename _Type, size_t _Size >
    _Type* end(_Type(&in_array)[_Size])
    {
        return (&in_array[0] + _Size);
    }

    template< typename _Type, size_t _Size >
    _Type const* end(_Type const (&in_array)[_Size])
    {
        return (&in_array[0] + _Size);
    }

}
